package com.fsbm.ctech.maxis.ebpsbackend;

/*
* acctLoad.java
*
* Created on October 24, 2002, 10:24 AM
*/
import java.io.*;
import java.util.Date;
import java.util.Properties;
import com.checkfree.isolutions.customer.persist.*;
import com.checkfree.isolutions.persist.*;
import com.checkfree.isolutions.statement.persist.*;
import com.checkfree.isolutions.utility.*;
import com.fsbm.ctech.maxis.ebpsbackend.InsertAcctExt;

/**
 * Module Id    :
 * Description  :  The <code>acctLoad</code> class uploads account information to the database server.
 *
 * @version 1.00
 * @author  Jason R. Sarmiento
 *
 * @param phoneDtlFile  The Telephone detail file
 *
 * @return 1 for success and 0 for failure
 * @exception
 *
 * @Change History
 * @--------------
 * @Author      :
 * @Date        :
 * @Description :
 */
public class AcctLoad extends Thread {
    private static int maxThread = 10;
    private static String dtoverride = new String();
    private static String dtcurrent = new String();
    private static String cfiPath = new String();
    private static String acctPath = new String();
    private static String acctName = new String();
    private static String acctFilename = new String();
    private static boolean err = false;
    private static boolean help = false;
    private String logFilename = new String();
    private String expLogFileName = new String();
    private String splitFilename = new String();
    private int fileCtr = 0;

    /** Creates new acctLoad */
    public AcctLoad(String logFilename, String splitFilename, int fileCtr,String expLogFileName) {
        this.logFilename = logFilename;
        this.splitFilename = splitFilename;
        this.fileCtr = fileCtr;
        this.expLogFileName = expLogFileName;
    }
    public void run() {
        PrintWriter logOut = null;
        boolean errFlag = false;

        // start of process
        try {

            // open log file
            this.logFilename = this.logFilename.concat("." + fileCtr);
            this.expLogFileName = this.expLogFileName.concat("." + fileCtr);
            try {
                logOut = new PrintWriter(new java.io.BufferedWriter(new java.io.FileWriter(this.logFilename)));
            }
            catch(IOException e) {
                System.err.println("Error creating file. " + e);
            }
            Date currentDate = new Date();
            java.text.DateFormat dtExecFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

            // log execution start time
            displayWriteToFile(logOut, "\nProcess[" + this.fileCtr + "] started at " + dtExecFormat.format(currentDate) + "\n");

            // open account information file for reading
            java.io.BufferedReader acctIn = new java.io.BufferedReader(new java.io.FileReader(this.splitFilename));

            // initialize counter
            int procCtr = 0;
            int phoneCtr = 0;
            int lineSkippedCtr = 0;
            //int persisServerCtr = 0;

            // initialize dummy account number
            String currentAcctId = new String();
            String[][] acctDtlArray = new String[lineCount(this.splitFilename)][7];
            displayWriteToFile(logOut, "\nProcess[" + this.fileCtr + "] Setting Accounts Properties...\n");
            try {

                String buffer = new String();
                int acctCounter = 0;
                while((buffer = acctIn.readLine()) != null) {
					String acctId = "";
					String phoneDtls = "";
					String custGroup = "";
					String supIndicator = "";
					String acctKey = "";

                    java.util.StringTokenizer strTokenizer = new java.util.StringTokenizer(buffer, ",");
                    while(strTokenizer.hasMoreTokens()) {
						acctId = strTokenizer.nextToken();
						phoneDtls = strTokenizer.nextToken();
						custGroup = strTokenizer.nextToken();
						supIndicator = strTokenizer.nextToken();
						try {
							acctKey = strTokenizer.nextToken();
						} catch (Exception e) {
							acctKey = "";
						}
					}

                    java.util.StringTokenizer phoneTokenizer = new java.util.StringTokenizer(phoneDtls, "|");

                    // magic number 3: count of tokens
                    if(phoneTokenizer.countTokens() < 3) {
                        displayWriteToFile(logOut, "\nProcess[" + this.fileCtr + "] Line skipped: Incorrect format [" + buffer + "]\n");
                        lineSkippedCtr++;
                        continue;
                    }
                    String phoneNo = phoneTokenizer.nextToken();
                    String status = phoneTokenizer.nextToken();
                    String serviceType = phoneTokenizer.nextToken();

                    // check if different acct id
                    if(acctId.compareTo(currentAcctId) != 0) {
                        if(currentAcctId.length() > 0) {
                            displayWriteToFile(logOut, "Process[" + this.fileCtr + "] Phone number count: " + phoneCtr + "\n");
                        }

                        // initialize
                        phoneCtr = 0;
                        currentAcctId = acctId;
                        displayWriteToFile(logOut, "Process[" + this.fileCtr + "] Processing  " + currentAcctId);
                        procCtr++;

                    }
                    acctDtlArray[acctCounter][0] = currentAcctId;
                    acctDtlArray[acctCounter][1] = phoneNo;
                    acctDtlArray[acctCounter][2] = status;
                    acctDtlArray[acctCounter][3] = serviceType;
                    acctDtlArray[acctCounter][4] = acctKey;
                    acctDtlArray[acctCounter][5] = custGroup;
                    //acctDtlArray[acctCounter][6] = supIndicator;

                    phoneCtr++;
                    acctCounter++;
                    strTokenizer = null;
                    phoneTokenizer = null;
                }
            }
            catch(Exception ex) {
                errFlag = true;
                displayWriteToFile(logOut, "Process [" + this.fileCtr + "] -- EXCEPTION: " + ex.getClass() + " " + ex.getMessage());
            }
            catch(Throwable t) {
                errFlag = true;
                displayWriteToFile(logOut, "Process [" + this.fileCtr + "] -- EXCEPTION: " + t.getClass() + " " + t.getMessage());
            }
            finally {

                // clean up with deactivate
                //PersistServer.deactivate(true);
            }
            displayWriteToFile(logOut, "Process[" + this.fileCtr + "] Phone number count: " + phoneCtr + "\n");
            displayWriteToFile(logOut, "Process[" + this.fileCtr + "] Number of accounts processed : " + procCtr);
            displayWriteToFile(logOut, "Process[" + this.fileCtr + "] Lines skipped : " + lineSkippedCtr);
            acctIn.close();
            String dest = acctPath;
            if(errFlag == false) {

                // update accountext table
                displayWriteToFile(logOut, "\nProcess [" + this.fileCtr + "] Updating accountext table...\n");
                InsertAcctExt acctExt = new InsertAcctExt();
                acctExt.setLogStream(logOut);
                acctExt.setExceptionFileName(expLogFileName);
                acctExt.setPhoneDtl(acctDtlArray);
                acctExt.runProg();
                if(acctExt.isFailed()) {
                    dest = dest + "/err/" + acctName + "." + this.fileCtr;
                    displayWriteToFile(logOut, "\nProcess [" + this.fileCtr + "] An error occurred while updating the AccountExt table, please see log file for details.");
                }
                else {
                    dest = dest + "/done/" + acctName + "." + this.fileCtr;
                }

            // end of process
            }
            else {
                displayWriteToFile(logOut, "\nProcess [" + this.fileCtr + "] An error occurred while processing " + this.splitFilename + ", please see log file for details.");
            }

            // move split file
            displayWriteToFile(logOut, "moving " + this.splitFilename + " to " + dest);
            File acctFile = new File(this.splitFilename);
            acctFile.renameTo(new File(dest));

            // get execution end time
            Date endDate = new Date();
            displayWriteToFile(logOut, "\nProcess[" + this.fileCtr + "] ended at " + dtExecFormat.format(endDate) + "\n");
            String elapsed = getElapsed(currentDate, endDate);
            displayWriteToFile(logOut, "\nProcess[" + this.fileCtr + "] elapsed time: " + elapsed + "\n");
        }
        catch(Exception ex) {
            displayWriteToFile(logOut, "Process [" + this.fileCtr + "] -- EXCEPTION: " + ex.getClass() + " " + ex.getMessage());
        }
        finally {
            logOut.close();
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {

        // get environment variables



        try {

            Properties env = getEnvironment();
            cfiPath = env.getProperty("BGROOT");
            acctPath = env.getProperty("BACKEND_HOME") + "/acctfile";
        }
        catch(IOException ie) {
            System.err.println("Exception occurred: " + ie);
        }

//			  Poon : test on local
            //cfiPath = "D:\\Dev\\cfi\\v412";
            //acctPath = "D:\\Dev\\cfi\\v412\\data\\backend\\acctfile";

        // parse arguments
        parseArgs(args);
        if(err == true) {
            System.out.println("Error: Invalid argument!\n");
            return ;
        }

        // display program usage
        if(help == true) {
            usage();
            return ;
        }
        Date currentDate = new Date();
        java.text.DateFormat dtAcctFormat = new java.text.SimpleDateFormat("yyyyMMdd");
        java.text.DateFormat dtLogFormat = new java.text.SimpleDateFormat("yyyyMMddHHmmss");
        java.text.DateFormat dtExecFormat = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // open log file
        String fdate = dtLogFormat.format(currentDate);


        String logFilename = cfiPath + "/log/acct" + fdate + ".log";
        String expLogFilename = cfiPath + "/log/acctExp" + fdate + ".log";
//		Poon: test on local
        //String logFilename = cfiPath + "\\log\\acct" + fdate + ".log";
        //String expLogFilename = cfiPath + "\\log\\acctExp" + fdate + ".log";
        PrintWriter logOut = null;
        try {
            logOut = new PrintWriter(new java.io.BufferedWriter(new java.io.FileWriter(logFilename)));
        }
        catch(IOException e) {
            System.err.println("Error creating file. " + e);
        }
        printCTechSignature(logOut);

        // log execution start time
        displayWriteToFile(logOut, "\nExecution started at " + dtExecFormat.format(currentDate) + "\n");
        boolean errFlg = false;

        // start of process
        try {
            if(dtoverride.length() > 0) {
                acctName = "acct" + dtoverride + ".csv";

                acctFilename = acctPath + "/acct" + dtoverride + ".csv";
// Poon : test on local
                //acctFilename = acctPath + "\\acct" + dtoverride + ".csv";
            }
            else {
                dtcurrent = dtAcctFormat.format(currentDate);
                acctName = "acct" + dtcurrent + ".csv";

                acctFilename = acctPath + "/acct" + dtcurrent + ".csv";
// Poon : test on local
                //acctFilename = acctPath + "\\acct" + dtcurrent + ".csv";
            }

            // get file line count
            int fileLines = lineCount(acctFilename);
            int linesPerFile = fileLines / maxThread;
            int fileCtr = 0;
            int lineCtr = 0;
            PrintWriter splitOut = null;
            String splitFilename = new String();

            // open account information file for reading
            java.io.BufferedReader acctIn = new java.io.BufferedReader(new java.io.FileReader(acctFilename));

            // split file depending on the process count specified
            String buffer = new String();
            while((buffer = acctIn.readLine()) != null) {
                java.util.StringTokenizer strTokenizer = new java.util.StringTokenizer(buffer, ",");

                // magic number 4: count of tokens
                if(strTokenizer.countTokens() < 4) {
                    displayWriteToFile(logOut, "\nLine skipped: Incorrect format [" + buffer + "]\n");
                    continue;
                }
                if(lineCtr == linesPerFile) {
                    lineCtr = 0;
                    if(splitOut != null) {
                        splitOut.close();

                        // instantiate thread
                        displayWriteToFile(logOut, "Creating thread for : " + splitFilename + " -> " + fileCtr + "\n");
                        AcctLoad acctLoad = new AcctLoad(logFilename, splitFilename, fileCtr, expLogFilename);
                        acctLoad.start();
                    }
                }
                if(lineCtr == 0) {
                    fileCtr++;
                    splitFilename = acctFilename + "." + fileCtr;

                    // creates new file; overwrites if existing
                    splitOut = new PrintWriter(new java.io.BufferedWriter(new java.io.FileWriter(splitFilename)));
                }
                writeToFile(splitOut, buffer);
                lineCtr++;
            }
            if(splitOut != null) {
                splitOut.close();
            }
            if(lineCtr > 0) {

                // instantiate thread
                displayWriteToFile(logOut, "Creating thread for : " + splitFilename + " |-> " + fileCtr + "\n");
                AcctLoad acctLoad = new AcctLoad(logFilename, splitFilename, fileCtr, expLogFilename);
                acctLoad.start();
            }

            // end
            acctIn.close();
        }
        catch(FileNotFoundException fnfe) {
            displayWriteToFile(logOut, "File not found " + acctFilename);
            errFlg = true;
        }
        catch(Exception ex) {
            displayWriteToFile(logOut, "-- EXCEPTION: " + ex.getClass() + " " + ex.getMessage());
            errFlg = true;
        }
        catch(Throwable t) {
            displayWriteToFile(logOut, "-- EXCEPTION: " + t.getClass() + " " + t.getMessage());
        }

        // move account file
        if(errFlg == false) {
            String dest = acctPath + "/done/" + acctName;
            displayWriteToFile(logOut, "moving " + acctFilename + " to " + dest);
            File acctFile = new File(acctFilename);
            acctFile.renameTo(new File(dest));
        }

        // get execution end time
        Date endDate = new Date();
        displayWriteToFile(logOut, "\nExecution ended at " + dtExecFormat.format(endDate) + "\n");
        String elapsed = getElapsed(currentDate, endDate);
        displayWriteToFile(logOut, "Elapsed execution time: " + elapsed + "\n");
        logOut.close();
    }
    private static String getElapsed(Date startDate, Date endDate) {
        long elapsed = (endDate.getTime() - startDate.getTime()) / 1000;
        long hours, minutes, seconds;
        hours = elapsed / 3600;
        elapsed = elapsed - (hours * 3600);
        minutes = elapsed / 60;
        elapsed = elapsed - (minutes * 60);
        seconds = elapsed;
        return (hours + " hrs " + minutes + " mins " + seconds + " secs\n");
    }
    private static Properties getEnvironment() throws java.io.IOException {
        Properties env = new Properties();
        env.load(Runtime.getRuntime().exec("env").getInputStream());
        return env;
    }
    private static void parseArgs(String args[]) {
        for(int i = 0;i < args.length;i++) {
            if(args[i].toLowerCase().indexOf("-threadcount") != -1) {
                String buffer = args[i];
                int pos = buffer.indexOf("=");
                String strCount = buffer.substring(pos + 1);
                maxThread = Integer.parseInt(strCount);
            }
            if(args[i].toLowerCase().indexOf("-d") != -1) {
                String buffer = args[i];
                int pos = buffer.indexOf("d");
                dtoverride = buffer.substring(pos + 1);
            }
            if((args[i].compareToIgnoreCase("-?") == 0) || (args[i].compareToIgnoreCase("-h") == 0)) {
                help = true;
                break;
            }
            if((args[i].toLowerCase().indexOf("-d") == -1) && (args[i].toLowerCase().indexOf("-threadcount") == -1)) {
                err = true;
                break;
            }
        }
    }
    private static void usage() {
        System.out.println("acctLoad");
        System.out.println("Copyright (c) 2002 FSBM CTech Sdn Bhd (427095-M).");
        System.out.println("All rights reserved.\n");
        System.out.println("Usage : java AcctLoad [-dYYYYMMDD]>\n");
        System.out.println("where :");
        System.out.println("\t-dYYYYMMDD\t: overrides the system date");
        System.out.println("\t-ThreadCount\t: (optional) number of concurrent processes to initiate <default = 10>");
        System.out.println("\t-h\t\t: display this message");
        System.out.println("\t-?\t\t: display this message");
    }
    private static void printCTechSignature(PrintWriter out) {
        displayWriteToFile(out, "FSBM CTech Sdn Bhd (427095-M)");
        displayWriteToFile(out, "Copyright (C) FSBM CTech. All rights reserved.");
    }
    private synchronized static void displayWriteToFile(PrintWriter out, String buffer) {
        System.out.println(buffer);
        out.println(buffer);
    }
    private synchronized static void writeToFile(PrintWriter out, String buffer) {
        out.println(buffer);
    }
    private static int lineCount(String filename) {
        int lineCount = 0;
        try {
            LineNumberReader reader = new LineNumberReader(new FileReader(filename));
            while(reader.readLine() != null) {
                ;
            }
            lineCount = reader.getLineNumber();
        }
        catch(FileNotFoundException ignored) {

        }
        catch(IOException ignored) {

        }
        return lineCount;
    }
}
